package com.zoe.onelink.auth.runner;

import cn.hutool.core.lang.UUID;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.task.Task;
import cn.hutool.extra.spring.SpringUtil;
import com.zoe.onelink.auth.client.AuthRemoteClient;
import com.zoe.onelink.redis.util.RedisUtil;
import com.zoe.onelink.upms.common.constants.CacheConstants;
import com.zoe.onelink.upms.common.constants.SsoModeEnum;
import com.zoe.onelink.upms.common.constants.SystemConstants;
import lombok.extern.slf4j.Slf4j;
import org.springframework.core.env.Environment;
import org.springframework.data.redis.core.RedisTemplate;

import java.util.concurrent.atomic.AtomicInteger;

/**
 * <p>标题: </p>
 * <p>描述: </p>
 * <p>版权: Copyright (c) 2018</p>
 * <p>公司: 智业软件</p>
 *
 * @author LinHongKai
 * @date 2022-03-19 9:27
 */
@Slf4j
public class RedisCompareTask implements Task {

    private String schedulerId;

    private Environment environment = SpringUtil.getBean(Environment.class);

    private AuthRemoteClient authRemoteClient = SpringUtil.getBean(AuthRemoteClient.class);

    private RedisTemplate<String, Object> redisTemplate = SpringUtil.getBean("redisTemplate");

    private static final int MAX_RETRY_TIMES = 120;

    private volatile boolean isInterrupt = false;

    private AtomicInteger count = new AtomicInteger(0);


    @Override
    public void execute() {
        if(isInterrupt){
            interrupt();
            return;
        }
        // 服务ID，就是本服务的项目名
        String serviceId = getServiceId();
        if(StrUtil.isEmpty(serviceId)){
            log.info("serviceId为空，无法对比redis是否同源");
            interrupt();
            return;
        }

        // redisKey和redisValue，每次获取都是随机的一串uuid，并放入redis的HASH类型中
        String redisKey = UUID.randomUUID().toString();
        String redisValue = UUID.randomUUID().toString();
        RedisUtil.putMapValue(CacheConstants.REDIS_COMPARE_MAP, redisKey, redisValue);
        log.info("serviceId：{}，redisKey：{}，redisValue：{}", serviceId, redisKey, redisValue);

        // 将serviceId，redisKey，redisValue发送给授权服务进行对比，授权服务会从自己的redis中通过redisKey获取redisValue来进行比较，相等说明是同源redis
        Boolean isRedisEqual = authRemoteClient.redisIsEqual(serviceId, redisKey, redisValue);
        // 对比完就删除
        redisTemplate.opsForHash().delete(CacheConstants.REDIS_COMPARE_MAP, redisKey);

        // 尚未正确获取到结果，可能是授权服务尚未启动，也可能是接口报错
        // 重试达到阈值就中断掉任务
        if(isRedisEqual == null){
            log.info("重试第{}次，与授权服务对比redis是否为同一个实例，对比失败，重试超过{}次后将不再重试", count.get(), MAX_RETRY_TIMES);
            if(count.incrementAndGet() > MAX_RETRY_TIMES){
                interrupt();
            }
            return;
        }

        // 正确进行了比较，就中断任务
        SystemConstants.ssoMode = isRedisEqual ? SsoModeEnum.REDIS_EQUAL : SsoModeEnum.REDIS_DIFFERENT;
        log.info("redis比对完成，比较结果：{}", isRedisEqual ? "同源" : "不同源");
        interrupt();
    }


    /**
     * 获取本服务名
     * @return
     */
    private String getServiceId() {
        return environment.getProperty("spring.application.name");
    }


    /**
     * 中断任务，不再执行
     */
    public void interrupt(){
        isInterrupt = true;
        CronUtil.remove(schedulerId);
        CronUtil.stop();
    }


    public void setSchedulerId(String schedulerId) {
        this.schedulerId = schedulerId;
    }
}
